<!--
 The BSD 3-Clause License

 Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com)
 Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/)
 All rights reserved.
 node-red-contrib-iiot-opcua
-->

<script type="text/javascript">
  RED.nodes.registerType('OPCUA-IIoT-Method-Caller', {
    category: 'IIoT',
    color: '#ABCDEF',
    defaults: {
      connector: {type: "OPCUA-IIoT-Connector", required: true},
      objectId: {value: ""},
      methodId: {value: ""},
      methodType: {value: "basic", required: true},
      value: {value: null},
      justValue: {value: true},
      name: {value: ""},
      showStatusActivities: {value: false},
      showErrors: {value: false},
      inputArguments: {value: []}
    },
    inputs: 1,
    outputs: 1,
    align: "left",
    icon: "icon.png",
    label: function () {
      return this.name || "Method Caller";
    },
    labelStyle: function () {
      return this.name ? "node_label_italic" : "";
    },
    oneditprepare: function () {
      let node = this

      let tabs = RED.tabs.create({
        id: "node-input-method-tabs",
        onchange: function (tab) {
          $("#node-input-method-tabs-content").children().hide()
          $("#" + tab.id).show()
        }
      })

      tabs.addTab({
        id: "opcuaiiot-method-tab-settings",
        label: this._("opcua-iiot-contrib.tabs-label.settings")
      })

      tabs.addTab({
        id: "opcuaiiot-method-tab-argument",
        label: this._("opcua-iiot-contrib.tabs-label.argument")
      })

      // Argument Management
      node.inputArguments.forEach(function (element, index, array) {
        generateArgumentEntry(element, index);
      })

      function generateArgumentEntry (argument, id) {
        let container = $('<li/>', {
          style:
            "background: #fefefe; margin:0; padding:8px 0px; border-bottom: 1px solid #ccc;"
        })
        let row = $('<div id="row' + id + '"/>').appendTo(container)

        $('<i style="color: #eee; cursor: move;" class="node-input-method-argument-handle fa fa-bars"></i>').appendTo(row)

        let nameField = $('<input/>', {
          id: "node-input-method-argument-name" + id,
          class: 'methodArgumentName',
          type: "text",
          style: "margin-left:5px;width:20%;",
          placeholder: 'name'
        }).appendTo(row)

        let datatypeField = $('<select/>', {
          id: "node-input-method-argument-dataType" + id,
          class: 'methodArgumentDatatype',
          type: "text",
          style: "margin-left:5px;width:18%;",
        }).appendTo(row);

        $.getJSON('opcuaIIoT/plain/DataTypeIds', function (data) {
          $(data).each(function () {
            datatypeField.append($("<option>").attr('value', this).text(this));
          });

          datatypeField.val(argument.dataType)
        })

        let valueField = $('<input/>', {
          id: "node-input-method-argument-value" + id,
          class: 'methodArgumentValue',
          type: "text",
          style: "margin: 0 auto;width:43%;min-width:60px;margin-left:5px",
          placeholder: 'value'
        }).appendTo(row)

        nameField.val(argument.name)
        datatypeField.val(argument.dataType)
        valueField.val(argument.value)

        let finalspan = $('<span/>', {style: "float: right;margin-right: 10px;"}).appendTo(row)

        let removeArgumentButton = $('<a/>', {
          href: "#",
          class: "editor-button editor-button-small",
          style: "margin-top: 7px; margin-left: 5px;"
        }).appendTo(finalspan)

        $('<i/>', {class: "fa fa-remove"}).appendTo(removeArgumentButton)

        removeArgumentButton.click(function () {
          container.css({"background": "#fee"})
          container.fadeOut(300, function () {
            $(this).remove()
          });
        });

        $("#node-input-method-argument-container").append(container)
      }

      $("#node-input-method-argument-container").sortable({
        axis: "y",
        handle: ".node-input-method-argument-handle",
        cursor: "move"
      });

      $("#node-input-method-argument-container .node-input-method-argument-handle").disableSelection()
      let cacheItemCount = 0
      $("#node-input-method-argument-add").click(function () {
        cacheItemCount++
        generateArgumentEntry({name: '', dataType: '', value: ''}, cacheItemCount)
        // length is every time one more than index
        $("#node-input-method-argument-container-div").scrollTop($("#node-input-method-argument-container-div").get(0).scrollHeight)
      })

      // dialog handling
      function switchDialogResize () {
        let rows = $("#dialog-form>div:not(.node-input-method-argument-container-row)")
        let height = $("#dialog-form").height()

        rows.each(function (index, row) {
          height -= row.outerHeight(true)
        })

        let editorRow = $("#dialog-form>div.node-input-method-argument-container-row")
        height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")))
        $("#node-input-method-argument-container-div").css("height", height + "px")
      }

      $("#dialog").on("dialogresize", switchDialogResize)

      $("#dialog").on("dialogopen", function (ev) {
        let size = $("#dialog").dialog('option', 'sizeCache-switch')
        if (size) {
          $("#dialog").dialog('option', 'width', size.width)
          $("#dialog").dialog('option', 'height', size.height)
          switchDialogResize()
        } else {
          setTimeout(switchDialogResize, 10)
        }
      })

      $("#dialog").on("dialogclose", function (ev, ui) {
        $("#dialog").off("dialogresize", switchDialogResize)
      })
    },
    oneditsave: function () {
      let node = this

      let cacheArguments = $("#node-input-method-argument-container").children()
      node.inputArguments = []
      cacheArguments.each(function () {
        node.inputArguments.push({
          name: $(this).find(".methodArgumentName").val(),
          dataType: $(this).find(".methodArgumentDatatype").val(),
          value: $(this).find(".methodArgumentValue").val()
        })
      })

      // console.log('well done editsave ...')
    }

  });
</script>

<script type="text/x-red" data-template-name="OPCUA-IIoT-Method-Caller">
    <div class="form-row">
        <ul style="background: #fff; min-width: 600px; margin-bottom: 20px;" id="node-input-method-tabs"></ul>
    </div>
    <div id="node-input-method-tabs-content" style="min-height: 170px;">
        <div id="opcuaiiot-method-tab-settings" style="display:none">
            <div class="form-row" style="min-width:640px">
                <label for="node-input-connector"><i class="icon-globe"></i> <span data-i18n="opcua-iiot-contrib.label.connector"></span></label>
                <input type="text" id="node-input-connector">
            </div>
            <div class="form-row">
                <label for="node-input-objectId"><i class="icon-tasks"></i> <span data-i18n="opcua-iiot-contrib.label.objectId"></span></label>
                <input type="text" id="node-input-objectId" placeholder="ns=0;s=Server or ns=0;i=2253">
            </div>
            <div class="form-row">
                <label for="node-input-methodId"><i class="icon-tasks"></i> <span data-i18n="opcua-iiot-contrib.label.methodId"></span></label>
                <input type="text" id="node-input-methodId" placeholder="ns=1;s=Bark or ns=1;i=VendorName-Bark">
            </div>
            <div class="form-row">
                <label for="node-input-methodType"><i class="icon-tasks"></i> <span data-i18n="opcua-iiot-contrib.label.methodType"></span></label>
                <select type="text" id="node-input-methodType">
                    <option value="basic">Basic</option>
                    <option value="complex">Complex</option>
                </select>
            </div>
            <div class="form-row">
                <label for="node-input-value"><i class="icon-tag"></i> <span data-i18n="opcua-iiot-contrib.label.value"></span></label>
                <input type="text" id="node-input-value" placeholder="">
            </div>
            <div class="form-row">
                <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
                <input type="text" id="node-input-name" placeholder="">
            </div>
            <hr>
            <div class="form-row">
                <label style="min-width:160px" for="node-input-justValue"><i class="fa fa-simplybuilt"></i>
                <span data-i18n="opcua-iiot-contrib.label.justValue"></span></label>
                <input type="checkbox" id="node-input-justValue" style="max-width:30px">
            </div>
            <hr>
            <div class="form-row">
                <label style="min-width:160px" for="node-input-showStatusActivities"><i class="fa fa-bolt"></i>
                <span data-i18n="opcua-iiot-contrib.label.showActivities"></span></label>
                <input type="checkbox" id="node-input-showStatusActivities" style="max-width:30px">
            </div>
            <div class="form-row">
                <label style="min-width:160px" for="node-input-showErrors"><i class="fa fa-exclamation-circle"></i>
                <span data-i18n="opcua-iiot-contrib.label.showErrors"></span></label>
                <input type="checkbox" id="node-input-showErrors" style="max-width:30px">
            </div>
        </div>
        <div id="opcuaiiot-method-tab-argument" style="display:none">
            <div class="form-row node-input-method-argument-container-row" style="margin-bottom: 0px;">
                <div id="node-input-method-argument-container-div"
                    style="box-sizing: border-box; border-radius: 5px;
                    height: 340px; padding: 5px; border: 1px solid #ccc; overflow-y:scroll;">
                    <ol id="node-input-method-argument-container" style=" list-style-type:none; margin: 0;"></ol>
                </div>
            </div>
            <div class="form-row">
                <a href="#" class="editor-button editor-button-small" id="node-input-method-argument-add"
                style="margin-top: 4px;"><i class="fa fa-plus"></i>
                <span data-i18n="opcua-iiot-contrib.label.addButton"></span></a>
            </div>
        </div>
    </div>
</script>

<script type="text/x-red" data-help-name="OPCUA-IIoT-Method-Caller">
    <h2>OPC UA IIoT Method Caller</h2>

    <p>The Node is to call a basic or complex method on the OPC UA server.</p>

    <h3>Input</h3>

    <p>If the settings of the node are filled, then a simple inject will work,
    otherwise the incoming has to receive a complex message with all parameters.</p>

    <p>You need to add your XML definition of types and attributes to the server.</p>

    <div>
        <strong>Simple event message payload could be a simple inject if the node parameters are filled or
        you have to send the parameters via msg object like:
        </strong>

        <pre>msg.payload.</pre>

        <ul>
            <li>objectId (Object-Id)
            <li>methodId (Method-Id)
            <li>inputArguments (Array)
                <ul>
                    <li>name (just to name the method parameter - has no effect to later use for now)
                    <li>dataType (all node-opcua DataTypes)
                    <li>value (value or Variant as expected from node-opcua)
                </ul>
            <li>methodType (basic, complex)
        </ul>
    </div>

    <p>The settings in that node will override incoming data if the msg property is empty or undefined.</p>

    <div>
        <strong>Complex event message:</strong>
        <ul>
            <li>objectId (Object-Id)
            <li>methodId (Method-Id)
            <li>inputArguments (Array)
            <ul>
                <li>dataType
                <li>value
            </ul>
            <li>methodType
            <li>nodetype
        </ul>
    </div>

    <h3>Output</h3>
    <div>
        <strong>Event message:</strong>
        <ul>
            <li>payload (Array)
            <ul>
                <li>statusCode
                <li>inputArgumentResults (Array)
                <li>inputArgumentDiagnosticInfos (Array)
                <li>outputArguments (Array)
            </ul>
            <li>definitionResults
            <ul>
                <li>methodId
                <li>methodDefinition
            </ul>
            <li>nodetype (method)
            <li>methodType
        </ul>
    </div>

    <strong>Name</strong>
    <p>Name in the flow of Node-RED.</p>

    <p>Set showErrors to get errors from node-opcua on browse.</p>
</script>
